package com.yxw.spring6.annoaop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect //切面类
@Component
public class LogAspect {
    /**
     * 通知类型
     * 前置 @Before
     * 返回 @AfterReturning
     * 异常 @AfterThrowing
     * 后置 @After
     * 环绕 @Around
     */

    //前置通知 value=切入点表达式配置切入点
    @Before(value = "execution(public int com.yxw.spring6.annoaop.CalculatorImpl.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        //joinPoint.getArgs() 获取通知的目标方法参数
        Object[] args = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger1-->前置通知, 方法名称: " + methodName + ", 参数" + Arrays.toString(args));
    }

    //后置通知
    @After(value = "execution(* com.yxw.spring6.annoaop.CalculatorImpl.*(..))")
    public void afterMethod(JoinPoint joinPoint){
        //JoinPoint 得到通知的一些信息
        //joinPoint.getSignature().getName() 获取增强的目标方法名
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger-->后置通知, 方法名称: " + methodName);
    }

    //返回通知
    //返回通知能得到增强的目标方法的返回值,returning => 给返回值设置名称
    @AfterReturning(value = "pointcut()",returning = "result")
    public void afterReturningMethod(JoinPoint joinPoint,Integer result){

        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger-->返回通知, 方法名称: " + methodName + ", 返回结果: " + result);
    }

    // throwing => 给返回的异常信息设置别名 形参里的名字必须和设置的别名一样
    //异常通知 可以获取出现的异常信息
    @AfterThrowing(value = "execution(* com.yxw.spring6.annoaop.CalculatorImpl.*(..))",throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinPoint,Throwable ex){
        //JoinPoint 得到通知的一些信息
        //joinPoint.getSignature().getName() 获取增强的目标方法名
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger-->异常通知, 方法名称: " + methodName + ", 异常信息: " + ex);
    }

    //环绕通知
    @Around("execution(* com.yxw.spring6.annoaop.CalculatorImpl.*(..))")
    //ProceedingJoinPoint 有更强大的方法
    public Object aroundMethod(ProceedingJoinPoint joinPoint){

        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argsStr = Arrays.toString(args);
        Object result = null;
        try {
            System.out.println("环绕通知 目标方法之前,参数:" + argsStr);
            //调用目标方法
             result = joinPoint.proceed();
            System.out.println("环绕通知 目标方法返回之后");

        }catch (Throwable throwable){
            System.out.println("环绕通知 目标方法出现异常 异常信息:" + throwable);
        }finally {
            System.out.println("环绕通知 目标方法执行完后");
        }
        return result;
    }

    //重用切入点表达式
    @Pointcut(value = "execution(* com.yxw.spring6.annoaop.CalculatorImpl.*(..))")
    public void pointcut(){}
}
